package com.xneure.code;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import com.xneure.utils.JsonUtil;

public abstract class NioSocket{
	private int readLength = 1024;
	private Selector selector;
	private Thread thread;
	private ByteBuffer buffer = ByteBuffer.allocate(readLength);
	private SocketChannel currSocket;
	{
		try{
			selector = Selector.open();
		}catch(IOException e){
		}
	}

	public Selector getSelector(){
		return selector;
	}

	public void setSelector(Selector selector){
		this.selector = selector;
	}

	public void setReadLength(int readLength){
		this.readLength = readLength;
		buffer = ByteBuffer.allocate(readLength);
	}

	void listenHandler(SocketChannel channel){
		listenHandler(null,channel);
	}

	void listenHandler(Selector s,SocketChannel channel){
		try{
			boolean async = null == s;
			Selector cSelector = async ? Selector.open() : s;
			channel.configureBlocking(false);
			channel.register(cSelector,SelectionKey.OP_READ);
			if(async){
				remote(cSelector);
			}
		}catch(IOException e){
			e.printStackTrace();
		}
	}

	private void remote(final Selector cSelector){
		Thread rListen = new Thread(new Runnable(){
			@Override
			public void run(){
				try{
					listen(cSelector);
				}catch(IOException e){
				}
			}
		});
		rListen.start();
	}

	void listen() throws IOException{
		if(thread == null){
			thread = new Thread(new Runnable(){
				@Override
				public void run(){
					try{
						listen(selector);
					}catch(IOException e){
					}
				}
			});
			thread.start();
		}else{
			thread.run();
		}
	}

	public void disconnect(){
		thread.interrupt();
	}

	void listen(Selector selector) throws IOException{
		while(true){
			try{
				if(selector.select(100) == 0){
					if(thread.isInterrupted()){
						return;
					}
					continue;
				}
				Iterator<SelectionKey> ite = selector.selectedKeys().iterator();
				while(ite.hasNext()){
					SelectionKey key = ite.next();
					ite.remove();
					if(key.channel() instanceof SocketChannel){
						currSocket = (SocketChannel)key.channel();
					}
					if(key.isReadable()){
						currSocket = (SocketChannel)key.channel();
						int read = currSocket.read(buffer);
						receiveMsg(buffer.array(),read);
					}else{
						event(key);
					}
				}
			}catch(Exception e){
				return;
			}
		}
	}

	abstract void event(SelectionKey key) throws IOException;

	abstract void receiveMsg(byte[] data,int length);

	void sendObject(Object data){
		sendBytes(JsonUtil.toJson(data).getBytes());
	}

	void sendBytes(byte[] data){
		sendBytes(currSocket,data);
	}

	void sendObject(SocketChannel sc,Object data){
		sendBytes(sc,JsonUtil.toJson(data).getBytes());
	}

	void sendBytes(SocketChannel sc,byte[] data){
		try{
			ByteBuffer outbuffer = ByteBuffer.wrap(data);
			sc.write(outbuffer);
		}catch(IOException e){
		}
	}
}
